/*
* Copyright (C) Microsoft. All rights reserved.  
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not 
* use this file except in compliance with the License.  You may obtain a copy 
* of the License at http://www.apache.org/licenses/LICENSE-2.0  
* 
* THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 
* WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 
* MERCHANTABLITY OR NON-INFRINGEMENT. 
*
* See the Apache License, Version 2.0 for specific language governing 
* permissions and limitations under the License.
*
*/

#pragma once

#include <db/db_interfaces.h>
#include <db/db_error.h>
#include <db/db_field_definition_t.h>

namespace test_wrappers { namespace storage {

template<class T>
class field_instance_t_base :
    public field_instance
{
public:
    // instantiation
    field_instance_t_base() :
        _fieldInstanceId(0),
        _userFieldId(0),
        _type(0),
        _fixed(true),
        _autoIncrement(false)
    {
    }

    field_instance_t_base(
        const field_definition_t<T>& fieldDefinition,
        const field_id& fieldInstanceId) :
        _fieldInstanceId(fieldInstanceId),
        _userFieldId(fieldDefinition.userId()),
        _name(fieldDefinition.name()),
        _type(fieldDefinition.type()),
        _fixed(fieldDefinition.fixed()),
        _autoIncrement(fieldDefinition.autoIncrement())
    {
    }

    // getters
    field_id fieldInstanceId() const
    {
        return _fieldInstanceId;
    }

    field_id userFieldId() const
    {
        return _userFieldId;
    }

    std::wstring name() const
    {
        return _name;
    }

    field_type type() const
    {
        return _type;
    }

    bool fixed() const
    {
        return _fixed;
    }

    bool autoIncrement() const
    {
        return _autoIncrement;
    }

private:
    field_id _fieldInstanceId;
    field_id _userFieldId;
    std::wstring _name;
    field_type _type;
    bool _fixed;
    bool _autoIncrement;
};

template<class T>
class field_instance_t :
    public field_instance_t_base<T>
{
public:
    field_instance_t(
        const field_definition_t<T>& fieldDefinition,
        const field_id& fieldInstanceId) :
        field_instance_t_base<T>(fieldDefinition, fieldInstanceId)
    {
    }

    unsigned int codePage() const
    {
        throw std::logic_error("field_instance_t::codePage() is not supported for this type.");
        return 0;
    }

    unsigned long maxBufferSizeInBytes() const
    {
        throw std::logic_error("field_instance_t::maxBufferSizeInBytes() is not supported for this type.");
        return 0;
    }
};

template<>
class field_instance_t<std::wstring> :
    public field_instance_t_base<std::wstring>
{
public:
    field_instance_t(
        const string_field& fieldDefinition,
        const field_id& fieldInstanceId) :
        field_instance_t_base<std::wstring>(fieldDefinition, fieldInstanceId),
            _codePage(fieldDefinition.codePage()),
            _maxBufferSizeInBytes(fieldDefinition.maxBufferSizeInBytes())
    {
    }

    unsigned int codePage() const
    {
        return _codePage;
    }

    unsigned long maxBufferSizeInBytes() const
    {
        return _maxBufferSizeInBytes;
    }

private:
    unsigned int _codePage;
    unsigned long _maxBufferSizeInBytes;
};

template<>
class field_instance_t<binary_blob> :
    public field_instance_t_base<binary_blob>
{
public:
    field_instance_t(
        const blob_field& fieldDefinition,
        const field_id& fieldInstanceId) :
        field_instance_t_base<binary_blob>(fieldDefinition, fieldInstanceId),
            _maxBufferSizeInBytes(fieldDefinition.maxBufferSizeInBytes())
    {
    }

    unsigned int codePage() const
    {
        throw std::logic_error("field_instance_t::codePage() is not supported for this type.");
        return 0;
    }

    unsigned long maxBufferSizeInBytes() const
    {
        return _maxBufferSizeInBytes;
    }

private:
    unsigned long _maxBufferSizeInBytes;
};

#if 0
template<>
class field_instance_t<std::wstring> :
    public field_instance
{
public:

    field_instance_t(
        const string_field& fieldDefinition,
        const field_id& fieldInstanceId) :
        _fieldDefinition(fieldDefinition),
        _fieldInstanceId(fieldInstanceId)
    {
    }

    field_id fieldInstanceId() const
    {
        return _fieldInstanceId;
    }

    const field_definition& fieldDefinition() const
    {
        return _fieldDefinition;
    }

    string_field fieldDefinitionT() const
    {
        return _fieldDefinition;
    }

private:
    string_field _fieldDefinition;
    field_id _fieldInstanceId;
};

template<>
class field_instance_t<binary_blob> :
    public field_instance
{
public:

    field_instance_t(
        const blob_field& fieldDefinition,
        const field_id& fieldInstanceId) :
        _fieldDefinition(fieldDefinition),
        _fieldInstanceId(fieldInstanceId)
    {
    }

    field_id fieldInstanceId() const
    {
        return _fieldInstanceId;
    }

    const field_definition& fieldDefinition() const
    {
        return _fieldDefinition;
    }

    blob_field fieldDefinitionT() const
    {
        return _fieldDefinition;
    }

private:
    blob_field _fieldDefinition;
    field_id _fieldInstanceId;
};
#endif
std::shared_ptr<field_instance> createFieldInstance(
    const std::shared_ptr<field_definition>& fieldDefinition,
    const field_id& fieldInstanceId);

}} // test_wrappers::storage
